package com.cybertron.lockdown.spider.handler;

import com.alibaba.fastjson.JSON;
import com.cybertron.lockdown.spider.SpiderRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import us.codecraft.webmagic.Spider;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by xiezhouyan on 15-1-20.
 */
public class HandleRequest extends Thread {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final ExecutorService SERVICE = Executors.newSingleThreadExecutor();


    private final Socket socket;

    private final SpiderRunner runner;

    private final Scanner scanner;


    public HandleRequest(SpiderRunner runner, Scanner scanner, Socket socket) {
        super();
        this.runner = runner;
        this.socket = socket;
        this.scanner = scanner;
    }

    @Override
    public void run() {

        Spider spider = runner.getSpider();
        BufferedReader in = null;
        PrintWriter out = null;
        Handler handler = null;
        try {
            in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            out = new PrintWriter(this.socket.getOutputStream());
            String line;
            while (isConnected() && (line = in.readLine()) != null) {
                HandleTask task;
                try {
                    task = JSON.parseObject(line, HandleTask.class);
                } catch (Exception e) {
                    logger.error("request data parse error", e);
                    continue;
                }
                if (HandleType.STOP_TASK == task.getHandleType()) {
                    handler.stop();
                    continue;
                }
                if (handler != null) {
                    handler.stop();
                }
                handler = getHandler(in, out, spider, task);
                if (handler == null) {
                    out.write(JSON.toJSONString(new HandleError(task.getHandleType(), "could't find handleType implement")));
                    out.flush();
                } else {
                    SERVICE.execute(handler);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
            handler.stop();
        } finally {
            handler.stop();
            if (out != null) {
                out.flush();
                out.close();
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("close inputstream error", e);
                }
            }

        }
    }

    private Handler getHandler(BufferedReader in, PrintWriter out, Spider spider, HandleTask task) {
        if (HandleType.COUNT == task.getHandleType()) {
            return new CountHandler(in, out, spider, task, this);
        } else if (HandleType.LOG == task.getHandleType()) {
            return new LogHandler(in, out, spider, task, this);
        }
        return null;
    }

    public boolean isConnected() {
        try {
            socket.sendUrgentData(0xFF);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public Scanner getLogScanner() {
        return scanner;
    }
}
